/*NOTICE

This software was produced for the U. S. Government
under Contract No. FA8721-09-C-0002, and is
subject to the Rights in Noncommercial Computer Software
and Noncommercial Computer Software Documentation Clause
(DFARS) 252.227-7014 (JUN 1995)

(c) 2009 The MITRE Corporation. All Rights Reserved.
*/
package org.mitre.xmltransform.uml21tospmif4;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.mitre.xmltransform.spmif.Device;

public class NodeHierarchy {
	//private static final Device LOCATION_NONE = new Device("<<NONE>>", null);

	public NodeHierarchy(Element pPerformanceScenarioElement, Element pExecutionGraphElement, String pName, NodeHierarchy pParentHierarchy, Device pLocation, String pExecutionStart) {
		mPerformanceScenarioElement = pPerformanceScenarioElement;
		mExecutionGraphElement = pExecutionGraphElement;
		//mParentHierarchy = pParentHierarchy;
		mExecutionStart = pExecutionStart;
		mRootNodes = new ArrayList<BaseNode>();
		mNodeMap = new HashMap<String, BaseNode>();
		mExecutingNodesMap = new HashMap<String, BaseNode>();
		mName = pName;
	}
	
	public Element getPerformanceScenarioElement() {
		return mPerformanceScenarioElement;
	}
	
	public Element getExecutionGraphElement() {
		return mExecutionGraphElement;
	}
	
	public String getName() {
		return mName;
	}
	
	public void addNode(BaseNode pNewNode) {
		BaseNode parent;
		if (pNewNode != null) {
			// add to step map
			addToStepMap(pNewNode);

			// add to parent
			String initiator = pNewNode.initiatedOn();
			parent = mExecutingNodesMap.get(initiator);
			if (parent != null) {
				parent.addChild(pNewNode);
			} else if (mExecutionStart.equals(initiator)) {
				mRootNodes.add(pNewNode);
			} else {
				throw new IllegalArgumentException("Node " + pNewNode.toString() + " could not be added.");
			}
			
			// do we add it to executing nodes map?
			if (!pNewNode.isReflexive() && pNewNode.canHaveChildren()) {
				// if there was already an executing node for the lifeline,
				// this will just replace it so that node is closed. we could
				// notify that node here that it is closed if that makes sense
				// at some point. just get the executesOn from executing nodes map
				// and if not null, call close method on it.
				mExecutingNodesMap.put(pNewNode.executesOn(), pNewNode);
			}
		}
	}
	
	private void addToStepMap(BaseNode pNewNode) {
		if (pNewNode != null) {
			mNodeMap.put(pNewNode.getUmlId(), pNewNode);
		}			
	}
	
	public int getNumberOfRootNodes() {
		return mRootNodes.size();
	}
	
	public BaseNode getRootNode(int pIndex) {
		return mRootNodes.get(pIndex);
	}
	
	private String mName;
	//private NodeHierarchy mParentHierarchy;
	private List<BaseNode> mRootNodes;
	private Map<String, BaseNode> mNodeMap;
	private Map<String, BaseNode> mExecutingNodesMap;
	private Element mPerformanceScenarioElement;
	private Element mExecutionGraphElement;
	private String mExecutionStart;
}